package uk.ac.lkl.common.associator.ui;



import java.awt.Color;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.Collection;

import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import uk.ac.lkl.common.associator.Associator;


public class HandlePanel extends JPanel {

    private int column;

    private Object element;

    // hack: temporary for while dragging
    private Collection<HandlePanel> targetHandles;

    // selected during dragging
    private HandlePanel targetHandle;

    private BasicAssociatorView associatorView;

    // to indicate whether associator call should be source,target or
    // target,source.
    private boolean leftToRight;


    public HandlePanel(BasicAssociatorView associatorView, int column,
            Object element, boolean leftToRight) {
        this.associatorView = associatorView;
        this.column = column;
        this.element = element;
        this.leftToRight = leftToRight;
        setBackground(Color.yellow);
        setBorder(BorderFactory.createEtchedBorder());

        addListeners();
    }


    private void addListeners() {
        addMouseListener();
        addMouseMotionListener();
    }


    private void addMouseListener() {
        addMouseListener(new MouseAdapter() {

            public void mousePressed(MouseEvent e) {
                HandlePanel.this.associatorView.pressPoint = SwingUtilities
                        .convertPoint(
                                      HandlePanel.this,
                                      e.getPoint(),
                                      associatorView);
                int column = HandlePanel.this.column;
                HandleSet handleSet = associatorView.getHandleSet();

                // hack - do better than this!
                Collection<HandlePanel> leftHandles = handleSet
                        .getLeftHandles();
                Collection<HandlePanel> rightHandles = handleSet
                        .getRightHandles();

                if (leftHandles.contains(HandlePanel.this))
                    targetHandles = rightHandles;

                if (rightHandles.contains(HandlePanel.this))
                    targetHandles = leftHandles;
            }


            public void mouseReleased(MouseEvent e) {
                associatorView.pressPoint = null;
                associatorView.dragPoint = null;
                associatorView.repaint();

                if (targetHandle == null)
                    return;

                Object sourceElement = HandlePanel.this.element;
                Object targetElement = targetHandle.getElement();
                Associator associator = associatorView.getAssociator();
                if (leftToRight)
                    associator.addAssociation(sourceElement, targetElement);

                else
                    associator.addAssociation(targetElement, sourceElement);
            }
        });

    }


    private void addMouseMotionListener() {
        addMouseMotionListener(new MouseMotionAdapter() {

            public void mouseDragged(MouseEvent e) {
                Point point = SwingUtilities.convertPoint(HandlePanel.this, e
                        .getPoint(), associatorView);

                Double minDistance = null;
                HandlePanel minHandle = null;

                for (HandlePanel handle : targetHandles) {
                    Rectangle bounds = handle.getBounds();
                    if (!bounds.contains(point))
                        continue;
                    // hacky to create
                    Point location = new Point(bounds.x + bounds.width / 2,
                            bounds.y + bounds.height / 2);
                    double distance = location.distance(point);
                    if (minDistance == null) {
                        minDistance = distance;
                        minHandle = handle;
                    }
                    else if (distance < minDistance) {
                        minDistance = distance;
                        minHandle = handle;
                    }
                }

                targetHandle = minHandle;
                associatorView.dragPoint = point;

                associatorView.repaint();
            }
        });

    }


    public Object getElement() {
        return element;
    }
}